//    Copyright (C) Kherty.  All rights reserved.
using System.Collections.Generic;
using System.Diagnostics;

namespace OpenLS.Spreadsheet
{
    using NodeList = HashListNoDuplicate<IDependencyNode>;

    internal sealed class DependencyBuilder
    {
        public DependencyBuilder(IDependencyNode rootNode)
        {
            AffectedNodes = new NodeList {rootNode};
            var toProcess = new Queue<IDependencyNode>();
            foreach (IDependencyNode c in rootNode.Dependents())
                toProcess.Enqueue(c);
            while (toProcess.Count > 0)
            {
                IDependencyNode c = toProcess.Dequeue();
                if (c == rootNode)
                    throw new CircularReferenceException();
                if (AffectedNodes.Contains(c))
                    continue;
                AffectedNodes.Add(c);
                foreach (IDependencyNode c2 in c.Dependents())
                {
                    if (c2 == rootNode)
                        throw new CircularReferenceException();
                    if (AffectedNodes.Contains(c2))
                        continue;
                    toProcess.Enqueue(c2);
                }
            }
        }

        public DependencyBuilder(IEnumerable<IDependencyNode> nodes)
        {
            AffectedNodes = new NodeList();

            foreach (IDependencyNode rootNode in nodes)
            {
                if (AffectedNodes.Contains(rootNode))
                    continue;
                var toProcess = new Queue<IDependencyNode>();
                foreach (IDependencyNode c in rootNode.Dependents())
                {
                    Debug.WriteLine("Enqueuing " + c + " from " + rootNode);
                    toProcess.Enqueue(c);
                }
                while (toProcess.Count > 0)
                {
                    IDependencyNode c = toProcess.Dequeue();
                    if (c == rootNode)
                        throw new CircularReferenceException();
                    if (AffectedNodes.Contains(c))
                        continue;
                    AffectedNodes.Add(c);
                    foreach (IDependencyNode c2 in c.Dependents())
                    {
                        if (c2 == rootNode)
                            throw new CircularReferenceException();
                        if (AffectedNodes.Contains(c2))
                            continue;
                        Debug.WriteLine("Enqueuing " + c2);
                        toProcess.Enqueue(c2);
                    }
                }
            }
        }

        public NodeList AffectedNodes { get; private set; }
    }
}